import Axios, {AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse} from 'axios'

import settle from 'axios/lib/core/settle'
import buildURL from 'axios/lib/helpers/buildURL'

import { useUserStore } from '@/store/modules/user'
import { getProductIdMap } from '@/utils/common';

// #ifdef H5
const baseURL: string = import.meta.env.VITE_API_BASE_URL || ''
// #endif
// #ifdef MP-WEIXIN || MP-QQ
import {apiHost} from '../../config'

const baseURL: string = apiHost.endsWith('/') ? apiHost.substring(0, apiHost.length - 1) : apiHost
// #endif

// 临时使用localStorage存储移动端productId到同应用pc端productId的映射
getProductIdMap().then(res => {
    uni.setStorageSync('productIdMap', JSON.stringify(res));
});

const axios = Axios.create({
    baseURL, // 基础 url
    withCredentials: true,
    timeout: 10000, // 超时 10s
    headers: {
        'X-Requested-With': 'XMLHttpRequest'
    }
})

axios.defaults.adapter = function (config) {
  return new Promise((resolve, reject) => {
    uni.request({
      method: config.method.toUpperCase(),
      url: config.baseURL + buildURL(config.url, config.params, config.paramsSerializer),
      header: config.headers,
      data: config.data,
      dataType: config.dataType,
      responseType: config.responseType,
      sslVerify: config.sslVerify,
      complete: function complete(response) {
        handleUnauthorized(response.statusCode)
        response = {
          data: response.data,
          status: response.statusCode,
          errMsg: response.errMsg,
          header: response.header,
          config: config
        }
        settle(resolve, reject, response)
      }
    })
  })
}


axios.interceptors.request.use(
    (config: AxiosRequestConfig) => {
        // 附加上token和uid
        const userStore = useUserStore()
        const token = userStore.getToken
        const uid = userStore.getUid
        if (!config.headers) {
            config.headers = {} as AxiosRequestHeaders
        }
        if (token) {
            config.headers['token'] = token
            if (uid) {
                config.headers['uid'] = uid
            }
        }
        // 临时默认处理移动端productId到同应用pc端productId的映射
        const productIdMap = JSON.parse(uni.getStorageSync('productIdMap') || '{}');
        if (userStore.productId && productIdMap[userStore.productId]) {
          config.headers['productid'] = productIdMap[userStore.productId];
        }
        // header中加入applicationId
        let applicationId = import.meta.env.VITE_APP_ID;
        if (applicationId) {
          const applicationIds = applicationId.split('h5_');
          applicationIds && applicationIds.length > 0 && (applicationId = applicationIds[1]);
        }
        if (applicationId) {
          config.headers['applicationId'] = applicationId;
        }
        if (userStore.tenantId) {
            config.headers['tenantid'] = userStore.tenantId
        }
        if (userStore.appid) {
            config.headers['appId'] = userStore.appid
        }
        config.headers['production'] = 'DPAs'
        config.headers['timestamp'] = new Date().getTime()
        return config
    },
    (error: any) => {
        return Promise.reject(error)
    }
)

axios.interceptors.response.use(
    response => {
        // 服务器正常返回
        const data = response.data
        if (response?.config?.responseType) {
            if (['arraybuffer', 'blob'].includes(response.config.responseType)) {
                return response
            }
        }
        // 判断http状态码为2xx
        if (response.status >= 200 && response.status < 300) {
            return response
        } else if (response.status === 401) {
            handleUnauthorized(response.status)
            return Promise.reject(response)
        } else {
            // 其他错误，直接抛出错误
            return Promise.reject(data.errorCode)
        }
    },
    error => {
        return Promise.reject({
            code: error.response.status,
            message: error.response.statusText
        })
    }
)

const handleUnauthorized = statusCode => {
    if (statusCode === 401) {
        const userStore = useUserStore()
        userStore.logout()
        uni.showToast({
          title: '登录过期，请重新登录',
          icon: 'none'
        })
        uni.reLaunch({
          url: '/pages/Login/Login'
        })
    }
}
export default axios

export function get<T = any, D = any>(
    url: string,
    params?: D,
    config?: AxiosRequestConfig<D>
): Promise<HttpResponse<T>> {
    const localConfig = config ? config : ({} as AxiosRequestConfig<D>)
    if (params) {
        localConfig.params = Object.assign({}, localConfig.params ? localConfig.params : {}, params)
    }
    return axios.get<HttpResponse<T>>(url, localConfig).then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
}

export function getWithErrorMessage<T = any, D = any>(
    url: string,
    params?: D,
    config?: AxiosRequestConfig<D>
): Promise<HttpResponse<T>> {
    const localConfig = config ? config : ({} as AxiosRequestConfig<D>)
    if (params) {
        localConfig.params = Object.assign({}, localConfig.params ? localConfig.params : {}, params)
    }
    return axios
        .get<HttpResponse<T>>(url, localConfig)
        .then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
        .then(resp => {
            if (resp.status !== 'success') {
                return Promise.reject(resp.errorMsg)
            }
            return resp
        })
}

export function post<T = any, D = any>(
    url: string,
    data?: D,
    config?: AxiosRequestConfig<D>
): Promise<HttpResponse<T>> {
    return axios.post<HttpResponse<T>>(url, data, config).then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
}

export function postWithErrorMessage<T = any, D = any>(
    url: string,
    data?: D,
    config?: AxiosRequestConfig<D>
): Promise<HttpResponse<T>> {
    return axios
        .post<HttpResponse<T>>(url, data, config)
        .then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
        .then(resp => {
            if (resp.status !== 'success') {
                return Promise.reject(resp.errorMsg)
            }
            return resp
        })
}

export function put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<HttpResponse<T>> {
    return axios.put<HttpResponse<T>>(url, data, config).then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
}
export function putWithErrorMessage<T = any, D = any>(
    url: string,
    data?: D,
    config?: AxiosRequestConfig<D>
): Promise<HttpResponse<T>> {
    return axios
        .put<HttpResponse<T>>(url, data, config)
        .then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
        .then(resp => {
            if (resp.status !== 'success') {
                return Promise.reject(resp.errorMsg)
            }
            return resp
        })
}

export function patch<T = any, D = any>(
    url: string,
    data?: D,
    config?: AxiosRequestConfig<D>
): Promise<HttpResponse<T>> {
    return axios.patch<HttpResponse<T>>(url, data, config).then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
}

export function del<T = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<HttpResponse<T>> {
    return axios.delete<HttpResponse<T>>(url, config).then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
}

// TODO add upload and download

export function request<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<HttpResponse<T>> {
    return axios.request<HttpResponse<T>>(config).then((resp: AxiosResponse<HttpResponse<T>>) => resp.data)
}

export function requestWithHeaders<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<HttpResponse<T>> {
  return axios.request<HttpResponse<T>>(config).then((resp: AxiosResponse<HttpResponse<T>>) => resp)
}
